<script setup lang="ts">
import { h, ref, reactive, onMounted } from 'vue'
import { NModal, NCard, NForm, NGrid, NSpace, NTag, NFormItem, NFormItemGi, NDynamicInput, NDatePicker, NRadioGroup, NRadio, NInput, NInputNumber, NSelect, NAutoComplete, NButton, NDataTable, NPagination, NPopconfirm, useNotification } from 'naive-ui'
import type { FormInst, FormRules, DataTableColumns } from 'naive-ui'

import { useDictStore } from '@/stores/dictStore'
import { useUserStore } from '@/stores/userStore'
import { useRouter } from 'vue-router'

import http from '@/tools/http'

const userStore = useUserStore()

type RowData = {
    jobName?: string
    jobGroup?: string
    jobStatus?: string
    beanName?: string
    startTime?: string
    endTime?: string
    triggerType?: string
    intervalSecond?: number
    repeatCount?: number
    cron?: string
    remark?: string
    jobData?: any
    formJobData?: any
}

const router = useRouter()
const dictStore = useDictStore()

const jobInfoTableColumns: DataTableColumns = [
    {
        title: "任务名称",
        key: "jobName",
        width: 100
    }, {
        title: "任务分组",
        key: "jobGroup",
        width: 100
    }, {
        title: "执行目标",
        key: "beanName",
        width: 100
    }, {
        title: "任务状态",
        key: "jobStatus",
        width: 100,
        render(rowData: RowData, rowIndex: number) {
            let statusType: "default" | "error" | "primary" | "info" | "success" | "warning" = "default"
            if (rowData.jobStatus === "COMPLETE") {
                statusType = "info"
            } else if (rowData.jobStatus === "ERROR") {
                statusType = "error"
            } else if (rowData.jobStatus === "NORMAL") {
                statusType = "success"
            } else if (rowData.jobStatus === "BLOCKED") {
                statusType = "warning"
            } else {
                statusType = "default"
            }
            return h(
                NTag,
                {
                    type: statusType
                },
                () => dictStore.dictItem("JOB_STATUS", rowData.jobStatus)
            )
        }
    }, {
        title: "调度类型",
        key: "triggerType",
        width: 100,
        render(rowData: RowData, rowIndex: number) {
            return dictStore.dictItem("SCHEDULE_TRIGGER_TYPE", rowData.triggerType)
        }
    }, {
        title: "执行时间间隔",
        key: "intervalSecond",
        width: 110,
        render(rowData: RowData, rowIndex: number) {
            if (rowData.intervalSecond) {
                return rowData.intervalSecond + 's'
            }
        }
    }, {
        title: "重复次数",
        key: "repeatCount",
        width: 100
    }, {
        title: "cron表达式",
        key: "cron",
        width: 120
    }, {
        title: "执行参数",
        key: "jobData",
        width: 150,
        render(rowData: RowData, rowIndex: number) {
            return JSON.stringify(rowData.jobData)
        }
    }, {
        title: "开始时间",
        key: "startTime",
        width: 160
    }, {
        title: "结束时间",
        key: "endTime",
        width: 160
    }, {
        title: "近一次执行时间",
        key: "previousFireTime",
        width: 160
    }, {
        title: "下次执行时间",
        key: "nextFireTime",
        width: 160
    }, {
        title: "备注",
        key: "remark",
        width: 160
    }, {
        title: "操作",
        key: "actions",
        width: 340,
        fixed: 'right',
        render(rowData: RowData, rowIndex: number) {
            return h(
                NSpace, null,
                () => [
                    userStore.hasAuth("job-schedule:start") ? h(
                        NButton,
                        {
                            size: "small",
                            disabled: rowData.jobStatus !== "NORMAL" && rowData.jobStatus !== "PAUSED",
                            onclick: () => {
                                if (rowData.jobStatus === "NORMAL") {
                                    pauseJob(rowData)
                                } else {
                                    resumeJob(rowData)
                                }

                            }
                        },
                        {
                            default: () => {
                                if (rowData.jobStatus === "NORMAL") {
                                    return "暂停"
                                } else {
                                    return "启动"
                                }
                            }
                        }
                    ) : null,
                    userStore.hasAuth("job-schedule:manual") ? h(
                        NButton,
                        {
                            size: "small",
                            onclick: () => manualInvoke(rowData)
                        },
                        { default: () => "手动调度" }
                    ) : null,
                    userStore.hasAuth("job-log") ? h(
                        NButton,
                        {
                            size: "small",
                            onclick: () => openJobLog(rowData)
                        },
                        { default: () => "日志" }
                    ) : null,
                    userStore.hasAuth("job-schedule:edit") ? h(
                        NButton,
                        {
                            size: "small",
                            onclick: () => openEditJobInfo(rowData)
                        },
                        { default: () => "编辑" }
                    ) : null,
                    userStore.hasAuth("job-schedule:delete") ? h(
                        NPopconfirm,
                        {
                            onPositiveClick: (e: MouseEvent) => deleteJobInfo()
                        },
                        {
                            trigger: () => {
                                return h(
                                    NButton,
                                    {
                                        size: "small",
                                        onclick: () => openDeleteJobInfo(rowData)
                                    },
                                    { default: () => "删除" }
                                )
                            },
                            default: () => { return "确认删除？" }
                        }
                    ) : null
                ]
            )
        }
    }
]

const jobInfoData = reactive<any>({
    list: [],
    pageNum: 1,
    pageSize: 10,
    pages: 1,
    total: 0
})

const jobInfoSearchFormValue = reactive({
    pageNum: 1,
    pageSize: 10,
    jobName: "",
    jobGroup: null,
    creator: ""
})

const jobInfoGroupOptions = reactive<any>([])

onMounted(() => {
    pageJobInfo()
    listJobGroup()
})

const visiable = ref<boolean>(false)
const title = ref<string>("")
const formRef = ref<FormInst | null>(null)
const formData = reactive<RowData>({
    jobName: "",
    jobGroup: "",
    beanName: "",
    startTime: undefined,
    endTime: undefined,
    triggerType: "1",
    intervalSecond: undefined,
    repeatCount: undefined,
    cron: "",
    remark: "",
    formJobData: []
})

const formRules: FormRules = ({
    jobName: {
        required: true,
        message: '请输入任务名称',
        trigger: ['input']
    },
    jobGroup: {
        required: true,
        message: '请输入任务分组',
        trigger: ['input']
    },
    beanName: {
        required: true,
        message: '请输入执行目标',
        trigger: ['input']
    },
    startTime: {
        required: true,
        message: '请输入开始时间',
        trigger: ['input']
    },
    endTime: {
        required: true,
        message: '请输入结束时间',
        trigger: ['input']
    },
    triggerType: {
        required: true,
        message: '请输入调度类型',
        trigger: ['input']
    },
    intervalSecond: {
        type: 'number',
        required: true,
        message: '请输入执行时间间隔',
        trigger: ['input']
    },
    repeatCount: {
        type: 'number',
        required: true,
        message: '请输入重复次数',
        trigger: ['input']
    },
    cron: {
        required: true,
        message: '请输入cron表达式',
        trigger: ['input']
    }
})

function pageNumChange(pageNum: number) {
    jobInfoSearchFormValue.pageNum = pageNum
    pageJobInfo()
}

function pageSizeChange(pageSize: number) {
    jobInfoSearchFormValue.pageSize = pageSize
    pageJobInfo()
}

function openAddJobInfo() {
    visiable.value = true
    title.value = "添加任务"
    formData.jobName = ""
    formData.jobGroup = ""
    formData.beanName = ""
    formData.startTime = undefined
    formData.endTime = undefined
    formData.triggerType = "1"
    formData.intervalSecond = undefined
    formData.repeatCount = undefined
    formData.cron = ""
    formData.remark = ""
    formData.formJobData = []
}

function openJobLog(row: any) {
    router.push({
        name: 'job-log',
        query: { jobName: row.jobName, jobGroup: row.jobGroup }
    })
}

function openEditJobInfo(row: any) {
    visiable.value = true
    title.value = "编辑任务"
    formData.jobName = row.jobName
    formData.jobGroup = row.jobGroup
    formData.beanName = row.beanName
    formData.startTime = row.startTime
    formData.endTime = row.endTime
    formData.triggerType = row.triggerType
    formData.intervalSecond = row.intervalSecond
    formData.repeatCount = row.repeatCount
    formData.cron = row.cron
    formData.remark = row.remark
    formData.jobData = row.jobData
    let formJobData = []
    for (let key in formData.jobData) {
        const data = {
            key: key,
            value: formData.jobData[key]
        }
        formJobData.push(data)
    }
    formData.formJobData = formJobData
}

function openDeleteJobInfo(row: any) {
    formData.jobName = row.jobName
    formData.jobGroup = row.jobGroup
    formData.beanName = row.beanName
    formData.startTime = row.startTime
    formData.endTime = row.endTime
    formData.triggerType = row.triggerType
    formData.intervalSecond = row.intervalSecond
    formData.repeatCount = row.repeatCount
    formData.cron = row.cron
    formData.remark = row.remark
    formData.jobData = row.jobData
    let formJobData = []
    for (let key in formData.jobData) {
        const data = {
            key: key,
            value: formData.jobData[key]
        }
        formJobData.push(data)
    }
    formData.formJobData = formJobData
}

function submit() {
    formRef.value?.validate((errors) => {
        if (!errors) {
            if (formData.formJobData) {
                let jobData: any = {}
                for (let i = 0; i < formData.formJobData.length; i++) {
                    jobData[formData.formJobData[i].key] = formData.formJobData[i].value
                }
                formData.jobData = jobData
            }
            console.log(formData)
            if (title.value === "添加任务") {
                addJobInfo()
            } else {
                updateJobInfo()
            }
            visiable.value = false
        }
    })
}

function pageJobInfo() {
    http.post("/schedule/page", jobInfoSearchFormValue).then(({ data }) => {
        jobInfoData.pageNum = data.data.pageNum
        jobInfoData.pageSize = data.data.pageSize
        jobInfoData.pages = data.data.pages
        jobInfoData.total = data.data.total
        jobInfoData.list.length = 0
        for (let i = 0; i < data.data.list.length; i++) {
            jobInfoData.list.push(data.data.list[i])
        }
    })
}

function listJobGroup() {
    http.post("/schedule/group").then(({ data }) => {
        jobInfoGroupOptions.length = 0
        for (let i = 0; i < data.data.length; i++) {
            jobInfoGroupOptions.push({
                label: data.data[i], value: data.data[i]
            })
        }
    })
}

const notification = useNotification()

function addJobInfo() {
    http.post("/schedule/add", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '添加成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}

function updateJobInfo() {
    http.post("/schedule/update", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '修改成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}

function deleteJobInfo() {
    http.post("/schedule/delete", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '删除成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}

function manualInvoke(row: any) {
    formData.jobName = row.jobName
    formData.jobGroup = row.jobGroup
    formData.beanName = row.beanName
    formData.startTime = row.startTime
    formData.endTime = row.endTime
    formData.triggerType = row.triggerType
    formData.intervalSecond = row.intervalSecond
    formData.repeatCount = row.repeatCount
    formData.cron = row.cron
    formData.remark = row.remark
    formData.jobData = row.jobData
    http.post("/schedule/invoke", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '调用成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}

function pauseJob(row: any) {
    formData.jobName = row.jobName
    formData.jobGroup = row.jobGroup
    formData.beanName = row.beanName
    formData.startTime = row.startTime
    formData.endTime = row.endTime
    formData.triggerType = row.triggerType
    formData.intervalSecond = row.intervalSecond
    formData.repeatCount = row.repeatCount
    formData.cron = row.cron
    formData.remark = row.remark
    formData.jobData = row.jobData
    http.post("/schedule/pause", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '暂停成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}

function resumeJob(row: any) {
    formData.jobName = row.jobName
    formData.jobGroup = row.jobGroup
    formData.beanName = row.beanName
    formData.startTime = row.startTime
    formData.endTime = row.endTime
    formData.triggerType = row.triggerType
    formData.intervalSecond = row.intervalSecond
    formData.repeatCount = row.repeatCount
    formData.cron = row.cron
    formData.remark = row.remark
    formData.jobData = row.jobData
    http.post("/schedule/resume", formData).then(({ data }) => {
        if (data.code === "0") {
            notification['success']({
                content: '启动成功',
                meta: `${data.msg}`,
                duration: 2500,
                keepAliveOnHover: true
            })
            pageJobInfo()
            listJobGroup()
        }
    })
}
</script>

<template>
    <div id="flame-container">
        <div class="search">
            <n-form :model="jobInfoSearchFormValue" inline label-placement="left">
                <n-form-item label="任务名称" path="jobName">
                    <n-input v-model:value="jobInfoSearchFormValue.jobName" placeholder="请输入任务名称" clearable />
                </n-form-item>
                <n-form-item label="任务分组" path="jobGroup">
                    <n-select style="width:196px" v-model:value="jobInfoSearchFormValue.jobGroup"
                        :options="jobInfoGroupOptions" placeholder="请输入任务分组" clearable />
                </n-form-item>
                <n-form-item label="创建人" path="beanName">
                    <n-input v-model:value="jobInfoSearchFormValue.creator" placeholder="请输入创建人" clearable />
                </n-form-item>
                <n-form-item>
                    <n-button attr-type="button" @click="pageJobInfo()">查询</n-button>
                </n-form-item>
            </n-form>
        </div>
        <div class="btn-group">
            <n-button v-if="userStore.hasAuth('job-schedule:add')" attr-type="button"
                @click="openAddJobInfo()">新增</n-button>
        </div>
        <div class="data-table">
            <n-data-table :scroll-x="2200" :scrollbar-props="{ trigger: 'none' }" style="height:100%" flex-height
                :columns="jobInfoTableColumns" :data="jobInfoData.list" :bordered="false" />
        </div>
        <div class="pagination">
            <n-pagination style="float:right" v-model:page="jobInfoData.pageNum" :page-size="jobInfoData.pageSize"
                :item-count="jobInfoData.total" :page-sizes="[5, 10, 30, 50, 100]" :on-update-page="pageNumChange"
                :on-update-page-size="pageSizeChange" show-quick-jumper show-size-picker />
        </div>
    </div>
    <n-modal v-model:show="visiable">
        <n-card style="width: 800px" :title="title">
            <n-form ref="formRef" :model="formData" :rules="formRules" label-width="106px" label-placement="left"
                require-mark-placement="left">
                <n-grid :cols="2" :x-gap="12">
                    <n-form-item-gi :span="1" label="任务名称" path="jobName">
                        <n-input v-model:value="formData.jobName" :disabled="title === '编辑任务'" placeholder="请输入任务名称"
                            clearable />
                    </n-form-item-gi>
                    <n-form-item-gi :span="1" label="任务分组" path="jobGroup">
                        <n-auto-complete v-model:value="formData.jobGroup" :disabled="title === '编辑任务'"
                            :options="jobInfoGroupOptions" placeholder="请输入任务分组" />
                    </n-form-item-gi>
                    <n-form-item-gi :span="1" label="开始时间" path="startTime">
                        <n-date-picker style="width:100%" type="datetime" v-model:formatted-value="formData.startTime"
                            value-format="yyyy-MM-dd HH:mm:ss"
                            :is-date-disabled="(ts: number) => ts < Date.now() - 86400000" placeholder="请输入开始时间"
                            clearable />
                    </n-form-item-gi>
                    <n-form-item-gi :span="1" label="结束时间" path="endTime">
                        <n-date-picker style="width:100%" type="datetime" v-model:formatted-value="formData.endTime"
                            value-format="yyyy-MM-dd HH:mm:ss" placeholder="请输入结束时间" clearable />
                    </n-form-item-gi>
                    <n-form-item-gi :span="1" label="调度类型" path="triggerType">
                        <n-radio-group v-model:value="formData.triggerType" name="radiogroup">
                            <n-space>
                                <div v-for="dict in dictStore.dict('SCHEDULE_TRIGGER_TYPE')" :key="dict.value">
                                    <n-radio v-if="dict.value !== '2'" :value="dict.value">
                                        {{ dict.label }}
                                    </n-radio>
                                </div>
                            </n-space>
                        </n-radio-group>
                    </n-form-item-gi>
                    <n-form-item-gi :span="1" label="执行目标" path="beanName">
                        <n-input v-model:value="formData.beanName" placeholder="请输入执行目标 spring-bean-name" clearable />
                    </n-form-item-gi>
                    <n-form-item-gi v-if="formData.triggerType === '0'" :span="1" label="执行时间间隔" path="intervalSecond">
                        <n-input-number style="width:100%" v-model:value="formData.intervalSecond" placeholder="请输入执行时间间隔"
                            clearable>
                            <template #suffix>
                                秒
                            </template>
                        </n-input-number>
                    </n-form-item-gi>
                    <n-form-item-gi v-if="formData.triggerType === '0'" :span="1" label="重复次数" path="repeatCount">
                        <n-input-number style="width:100%" v-model:value="formData.repeatCount" placeholder="请输入重复次数 -1=永久"
                            clearable>
                            <template #suffix>
                                次
                            </template>
                        </n-input-number>
                    </n-form-item-gi>
                    <n-form-item-gi v-if="formData.triggerType === '1'" :span="2" label="cron表达式" path="cron">
                        <n-input v-model:value="formData.cron" placeholder="请输入cron表达式" clearable />
                    </n-form-item-gi>
                    <n-form-item-gi :span="2" label="备注" path="remark">
                        <n-input v-model:value="formData.remark" placeholder="请输入备注" clearable />
                    </n-form-item-gi>
                    <n-form-item-gi :span="2" label="执行参数" path="formJobData">
                        <n-dynamic-input v-model:value="formData.formJobData" preset="pair" key-placeholder="Key"
                            value-placeholder="Value" />
                    </n-form-item-gi>
                </n-grid>
            </n-form>
            <template #footer>
                <n-space justify="end">
                    <n-button attr-type="button" @click="visiable = false">取消</n-button>
                    <n-button attr-type="button" @click="submit()">提交</n-button>
                </n-space>
            </template>
        </n-card>
    </n-modal>
</template>

<style scoped>
.display-flex-end {
    display: flex;
    width: 100%;
    justify-content: flex-end;
}
</style>